package session

import (
	"sync"
	"sync/atomic"

	log "gitee.com/lakertt/newtbig/logging"
	"gitee.com/lakertt/newtbig/msg/framepb"
)

type SessionMgr struct {
	sync.Map
	count int32
}

var sessionMgrSingleton *SessionMgr = nil
var once sync.Once

func GetSessionMgr() *SessionMgr {
	once.Do(func() {
		sessionMgrSingleton = new(SessionMgr)
	})
	return sessionMgrSingleton
}

func (sm *SessionMgr) AddSession(session *Session) bool {
	old := sm.GetSession(session.GetUID())
	if old != nil {
		sm.StopSession(old.GetUID())
	} else {
		atomic.AddInt32(&sm.count, 1)
	}
	_, loaded := sm.LoadOrStore(session.GetUID(), *session)
	return !loaded
}

func (sm *SessionMgr) StopSession(uid uint64) {
	if uid == 0 {
		return
	}
	ss := sm.GetSession(uid)
	if ss != nil {
		err := ss.OnStop()
		if err != nil {
			log.Logger.Error(err.Error())
		}
		sm.Delete(uid)
		atomic.AddInt32(&sm.count, -1)
	}

}

func (sm *SessionMgr) DelSession(uid uint64) {
	if uid == 0 {
		return
	}
	ss := sm.GetSession(uid)
	if ss != nil {
		sm.Delete(uid)
		atomic.AddInt32(&sm.count, -1)
	}
}

func (sm *SessionMgr) GetSession(uid uint64) *Session {
	user, ok := sm.Load(uid)
	if ok {
		ret, _ := user.(Session)
		return &ret
	} else {
		return nil
	}
}
func (sm *SessionMgr) StopAllSession() {
	sm.Range(func(key, value interface{}) bool {
		ret, _ := value.(Session)
		ss := &ret
		ss.OnStop()
		sm.count = atomic.AddInt32(&sm.count, -1)
		sm.Delete(key)
		log.Logger.Infof("SessionMgr closeSession key:%d", key)
		return true
	})
}

func (sm *SessionMgr) Count() int32 {
	return sm.count
}

func (sm *SessionMgr) BroatCast(msg *framepb.Msg) error {
	sm.Range(func(key, value interface{}) bool {
		ret, _ := value.(Session)
		ss := &ret
		err := ss.SendMsg(msg)
		if err != nil {
			log.Logger.Errorf("broatcast uid :%d err :%s", key.(uint64), err.Error())
		}
		return true
	})
	return nil
}

func (sm *SessionMgr) Receive(msg *framepb.Msg) error {
	ss := sm.GetSession(msg.UID)
	if ss == nil {
		log.Logger.Warnf("not fount session:%d  req:%d msgid:%d", msg.UID, msg.Seq, msg.ID)
		return nil
	}
	return ss.SendMsg(msg)

}
